#pragma once
#include<string>
#include <atomic>
#include "MQTTClient.h"
#include "ssiot/json.hpp"


#define SSIOT_LOGIN						"login"
#define SSIOT_LOGIN_ACK					"login/ack"
#define SSIOT_LOGOUT 					"logout"
#define SSIOT_SENSOR					"sensor"
#define SSIOT_SENSOR_GET				"sensor/get"
#define SSIOT_SENSOR_GET_ACK			"sensor/get/ack"
#define SSIOT_SENSOR_SET				"sensor/set"
#define SSIOT_SENSOR_SET_ACK			"sensor/set/ack"
#define SSIOT_PROPS						"props"
#define SSIOT_PROPS_GET					"props/get"
#define SSIOT_PROPS_GET_ACK				"props/get/ack"
#define SSIOT_PROPS_SET					"props/set"
#define SSIOT_PROPS_SET_ACK				"props/set/ack"
#define SSIOT_CONFIG					"config"
#define SSIOT_CONFIG_GET				"config/get"
#define SSIOT_CONFIG_GET_ACK			"config/get/ack"
#define SSIOT_CONFIG_SET				"config/set"
#define SSIOT_CONFIG_SET_ACK			"config/set/ack"
#define SSIOT_SUBDEVICE_CONFIG_GET		"config/get/subdevice"
#define SSIOT_SUBDEVICE_CONFIG_GET_ACK	"config/get/subdevice/ack"

class IoTMsg
{
public:
	IoTMsg() {};

	IoTMsg(const char* type, const char* to, const char* from, nlohmann::json data) {
		this->type = type;
		this->to = to;
		this->from = from;
		this->data = data;

		this->sid = 0;
		this->code = 0;

	};

	IoTMsg(const IoTMsg& obj)
	{
		this->type = obj.type;
		this->sid = obj.sid;
		this->to = obj.to;
		this->from = obj.from;
		this->code = obj.code;
		this->msg = obj.msg;
		this->data = obj.data;
	}

	~IoTMsg() {};

	int FromJson(const char* json);

	std::string ToJson(void);

public:
	std::string		type;

	int				sid;
	std::string		to;
	std::string		from;
	int				code;
	std::string		msg;

	nlohmann::json  data;
};

class Msgbus
{
public:
	Msgbus(std::string sn);
	~Msgbus();
	
	int Connect(std::string address, std::string username, std::string password);

	void Disconn(void);

	void Publish(IoTMsg msg);

	IoTMsg SyncPublish(IoTMsg msg);
	
	void Publish(std::string topic, const char* data, int len);

	void OnMessage(std::string topic, MQTTClient_message* message);

	void OnConnLost(char* cause);

private:
	std::string		sn_;
	MQTTClient		client_;

	IoTMsg				req_;
	IoTMsg				ack_;
	std::atomic_bool	sync_;
	std::atomic_bool	done_;
	std::atomic_uint	sid_;
};
